#include "Face.h"

Face::Face(std::string imagePath_, std::string modelPath_)
{
	rawImage = cv::imread(imagePath_.c_str());
	modelPath = modelPath_;
	mPosture = NULL;
	hasDetected = false;
	hasMarked = false;
	hasRotated = false;
	hasFeatured = false;
	hasCropped = false;
	featureArray = new float[FEATURE_SIZE];
}

Face::~Face()
{
	rawImage.release();
	detRes.release();
	rotRes.release();
	markRes.release();
	cropRes.release();
	finalBbox.clear();
	markPoint.clear();
	delete[] featureArray;
}

void Face::setPath(std::string imagePath_, std::string modelPath_)
{
	rawImage = cv::imread(imagePath_.c_str());
	modelPath = modelPath_;
	mPosture = NULL;
	hasDetected = false;
	hasMarked = false;
	hasRotated = false;
	hasFeatured = false;
	hasCropped = false;
	featureArray = new float[FEATURE_SIZE];
}

int Face::startDetect(int minsize) {
	if (hasDetected) return finalBbox.size();
	mDetect = new Detect(modelPath);
	ncnn::Mat in = ncnn::Mat::from_pixels(rawImage.data, ncnn::Mat::PIXEL_BGR2RGB, rawImage.cols, rawImage.rows);
	mDetect->getFinalBox(in, finalBbox);
	hasDetected = true;
	if (finalBbox.size() != 1) return finalBbox.size();
	maxBbox = finalBbox[0];
	if (maxBbox.area < minsize) return -1;
	delete mDetect;
	return 1;
}

cv::Mat Face::getDetectResult() {
	return detRes;
}

void Face::startRotate() {
	if (!hasDetected || hasRotated) return;
	mRotate = new Rotate();
	mRotate->start(rawImage, maxBbox, rotRes);
	hasRotated = true;
	delete mRotate;
}

cv::Mat Face::getRotateResult() {
	return rotRes;
}

void Face::startMark() {
	if (!hasDetected || hasMarked) return;
	mMark = new Mark(modelPath);
	int swidth = maxBbox.x2 - maxBbox.x1;
	int sheight = maxBbox.y2 - maxBbox.y1;

	cv::Rect subregion(maxBbox.x1, maxBbox.y1, swidth, sheight);
	cv::Mat subimage = rawImage(subregion);

	mMark->getMarkPoint(subimage, markPoint);
	for (int i = 0; i < markPoint.size(); i++) {
		if (i % 2 == 0) markPoint[i] = markPoint[i] * subimage.cols + maxBbox.x1;
		else markPoint[i] = markPoint[i] * subimage.rows + maxBbox.y1;
	}
	mPosture = new Posture(maxBbox, markPoint);
	hasMarked = true;
	delete mMark;
}

cv::Mat Face::getMarkResult() {
	rawImage.copyTo(markRes);
	for (int i = 0; i < markPoint.size() / 2; i++)
	{
		cv::Point x = cv::Point(int(markPoint[2 * i]), int(markPoint[2 * i + 1]));
		cv::circle(markRes, x, 0.1, cv::Scalar(0, 0, 255), 4, 8, 0);
	}
	return markRes;
}

int Face::getPosture() {
	if (!hasMarked) return -1;
	int poi = mPosture->getPos();
	return poi;
}

void Face::startCrop() {
	if (!hasMarked || hasCropped) return;
	mPosture->cropByPosture(rawImage, cropRes);
	hasCropped = true;
}

cv::Mat Face::getCropResult() {
	return cropRes;
}

void Face::startFeature() {
	if (!hasRotated || hasFeatured) return;
	mRecognize = new Recognize(modelPath);
	ncnn::Mat in = ncnn::Mat::from_pixels(rotRes.data, ncnn::Mat::PIXEL_BGR2RGB, rotRes.cols, rotRes.rows);
	mRecognize->start(in, featureArray);
	hasFeatured = true;
	delete mRecognize;
}

float* Face::getFeatureArray() {
	return featureArray;
}

float Face::calSimilarity(float* anotherArray) {
	if (!hasFeatured) return 0;
	float simularity = calculSimilar(anotherArray, featureArray, FEATURE_SIZE);
	return simularity;
}

cv::Mat Face::getRawImage() {
	return rawImage;
}

/*JNIEXPORT void JNICALL Java_FaceCppFuncs_faceInit
(JNIEnv *env, jobject object, jstring modelPath, jlong imageAddr, jint w, jint h, jint type) {
	rawImage = cv::Mat(h, w, type, (unsigned char*)imageAddr);
	Path = env->GetStringUTFChars(modelPath, 0);
	mPosture = NULL;
	hasDetected = false;
	hasMarked = false;
	hasRotated = false;
	hasFeatured = false;
	hasCropped = false;
	featureArray = new float[featureSize];
}

JNIEXPORT jint JNICALL Java_FaceCppFuncs_startDetect
(JNIEnv *env, jobject object, jint minsize) {
	if (hasDetected) return finalBbox.size();
	mDetect = new Detect(Path);
	ncnn::Mat in = ncnn::Mat::from_pixels(rawImage.data, ncnn::Mat::PIXEL_BGR2RGB, rawImage.cols, rawImage.rows);
	mDetect->getFinalBox(in, finalBbox);
	hasDetected = true;
	if (finalBbox.size() != 1) return finalBbox.size();
	maxBbox = finalBbox[0];
	if (maxBbox.area < minsize) return -1;
	delete mDetect;
	//if(writeInCpp) cv::imwrite("detectResult.jpg", detRes);
	return 1;
}

JNIEXPORT jlong JNICALL Java_FaceCppFuncs_getDetectResult
(JNIEnv *env, jobject object) {
	if (!hasDetected) return 0;
	rawImage.copyTo(detRes);
	cv::rectangle(detRes, cv::Point2i(maxBbox.x1, maxBbox.y1), cv::Point2i(maxBbox.x2, maxBbox.y2), cv::Scalar(0, 255, 0), 3);
	return (long long)&detRes;
}

JNIEXPORT void JNICALL Java_FaceCppFuncs_startRotate
(JNIEnv *env, jobject object) {
	if (!hasDetected || hasRotated) return;
	mRotate = new Rotate();
	mRotate->start(rawImage, maxBbox, rotRes);
	hasRotated = true;
	delete mRotate;
}

JNIEXPORT jlong JNICALL Java_FaceCppFuncs_getRotateResult
(JNIEnv *env, jobject object) {
	if (hasRotated) return (long long)&rotRes;
	else return 0;
}

JNIEXPORT void JNICALL Java_FaceCppFuncs_startMark
(JNIEnv *env, jobject object) {
	if (!hasDetected || hasMarked) return;
	mMark = new Mark(Path);
	int swidth = maxBbox.x2 - maxBbox.x1;
	int sheight = maxBbox.y2 - maxBbox.y1;

	cv::Rect subregion(maxBbox.x1, maxBbox.y1, swidth, sheight);
	cv::Mat subimage = rawImage(subregion);

	mMark->getMarkPoint(subimage, markPoint);
	for (int i = 0; i < markPoint.size(); i++) {
		if (i % 2 == 0) markPoint[i] = markPoint[i] * subimage.cols + maxBbox.x1;
		else markPoint[i] = markPoint[i] * subimage.rows + maxBbox.y1;
	}
	mPosture = new Posture(maxBbox, markPoint);
	hasMarked = true;
	delete mMark;
}

JNIEXPORT jlong JNICALL Java_FaceCppFuncs_getMarkResult
(JNIEnv *env, jobject object) {
	if (!hasMarked) return 0;
	rawImage.copyTo(markRes);
	for (int i = 0; i < markPoint.size() / 2; i++)
	{
		cv::Point x = cv::Point(int(markPoint[2 * i]), int(markPoint[2 * i + 1]));
		cv::circle(markRes, x, 0.1, cv::Scalar(0, 0, 255), 4, 8, 0);
	}
	return (long long)&markRes;
}

JNIEXPORT jint JNICALL Java_FaceCppFuncs_getPosture
(JNIEnv *env, jobject object) {
	if (!hasMarked) return -1;
	int poi = mPosture->getPos();
	return poi;
}

JNIEXPORT void JNICALL Java_FaceCppFuncs_startCrop
(JNIEnv *env, jobject object) {
	if (!hasMarked || hasCropped) return;
	mPosture->cropByPosture(rawImage, cropRes);
	hasCropped = true;
}

JNIEXPORT jlong JNICALL Java_FaceCppFuncs_getCropResult
(JNIEnv *env, jobject object) {
	if (!hasCropped) return 0;
	else return (long long)&cropRes;
}

JNIEXPORT void JNICALL Java_FaceCppFuncs_startFeature
(JNIEnv *env, jobject object) {
	if (!hasRotated || hasFeatured) return;
	mRecognize = new Recognize(Path);
	ncnn::Mat in = ncnn::Mat::from_pixels(rotRes.data, ncnn::Mat::PIXEL_BGR2RGB, rotRes.cols, rotRes.rows);
	mRecognize->start(in, featureArray);
	hasFeatured = true;
	delete mRecognize;
}

JNIEXPORT jfloatArray JNICALL Java_FaceCppFuncs_getFeatureArray
(JNIEnv *env, jobject object) {
	jfloatArray featureRes = env->NewFloatArray(featureSize);
	env->SetFloatArrayRegion(featureRes, 0, featureSize, featureArray);
	return featureRes;
}

JNIEXPORT jfloat JNICALL Java_FaceCppFuncs_calSimilarity
(JNIEnv *env, jobject object, jfloatArray anotherArray) {
	if (!hasFeatured) return 0;
	jfloat *anotherFeatureJ = env->GetFloatArrayElements(anotherArray, 0);
	float *anotherFeature = new float[featureSize];
	anotherFeature = anotherFeatureJ;
	float simularity = calculSimilar(anotherFeature, featureArray);
	env->ReleaseFloatArrayElements(anotherArray, anotherFeatureJ, 0);
	return simularity;
}

JNIEXPORT void JNICALL Java_FaceCppFuncs_clear
(JNIEnv *env, jobject object) {
	if (mPosture != NULL) delete mPosture;
	rawImage.release();
	detRes.release();
	rotRes.release();
	markRes.release();
	cropRes.release();
	finalBbox.clear();
	markPoint.clear();
	delete[] featureArray;
}*/